package Util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Anping Sec
 * @date 2022/05/11
 * description: 列表 <=> 树
 */
public class TreeAndListConvert<T extends ConvertBaseInfo<T>> {

    public TreeAndListConvert() {
    }

    /**
     * 获取searchId节点和其下级的树结构
     * @param searchId
     * @param list
     * @return
     */
    public T getCurNodeTree(String searchId, List<T> list){
        List<T> sysOrgList = getCurNodeAndChild(searchId, list);
        return listToTree(sysOrgList);
    }
    /**
     * 列表转树
     *
     * @param list
     * @return
     */
    public T listToTree(List<T> list) {
        if (list == null || list.size() == 0) return null;
        Map<String, T> dic = new HashMap<>();
        for (T e : list) {
            if (e.getNodeId().equals(e.getNodeParentId())) {
                error("treeNode exist circle error!");
            }
            dic.put(e.getNodeId(), e);
        }
        T node = null;
        int nullCount = 0;
        for (T item : list) {
            String pid = item.getNodeParentId();
            T parentNode = dic.get(pid);
            if (pid==null || "".equals(pid) || parentNode == null) {
                if (nullCount > 0) {
                    error("tree is error!");
                }
                //没有父级,该节点为树顶级
                nullCount++;
                node = item;
            } else {
                List<T> childList = parentNode.getChildList();
                childList.add(item);
            }
        }
        return node;
    }

    /**
     * 树转列表
     *
     * @param treeNode
     * @return
     */
    public List<T> treeToList(T treeNode) {
        List<T> list = new ArrayList<>();
        treeToList(treeNode, list);
        return list;
    }

    /**
     * 查询id为searchId的当前和下级
     *
     * @param searchId
     * @param list
     * @return
     */
    public List<T> getCurNodeAndChild(String searchId, List<T> list) {
        if (searchId==null  || list == null) {
            System.out.println("searchId and list must not be null!");
            return list;
        }
        Map<String, T> dic = new HashMap<>();
        for (T cur : list) {
            if (cur.getNodeId().equals(cur.getNodeParentId())) {
                error("treeNode exist circle error!");
            }
            cur.setRootPid(cur.getNodeParentId());
            dic.put(cur.getNodeId(), cur);
        }
        if (!dic.containsKey(searchId)) {
            System.out.println("The list don't exist searchId!");
            return new ArrayList<>();
        }
        String searchParentNodeId = dic.get(searchId).getNodeParentId();
        if (searchParentNodeId == null || "".equals(searchParentNodeId)
                || !dic.containsKey(searchParentNodeId)) {
            //search all list
            return list;
        }
        for (T node : list) {
            String rootId = node.getRootPid();
            if (!rootId.equals(searchId) || dic.get(rootId) != null) {
                findAndUnion(node, searchId, dic);
            }
        }
        return list.parallelStream().filter(e -> e.getRootPid().equals(searchId)
                || e.getNodeId().equals(searchId)).collect(Collectors.toList());
    }

    /**
     * mark
     *
     * @param node
     * @param searchId
     * @param dic
     * @return
     */
    private T findAndUnion(T node, String searchId, Map<String, T> dic) {
        T parentNode = dic.get(node.getRootPid());
        if (parentNode == null || searchId.equals(node.getNodeId())) {
            return node;
        }
        T rootNode = findAndUnion(parentNode, searchId, dic);
        node.setRootPid(rootNode.getNodeId());
        return rootNode;
    }

    private void treeToList(T treeNode, List<T> list) {
        if (treeNode == null || list == null) return;
        list.add(treeNode);
        List<T> childList = treeNode.getChildList();
        if (childList == null) return;
        for (T t : childList) {
            treeToList(t, list);
        }
    }

    public void error(String msg) {
        throw new RuntimeException(msg);
    }
}
